package top.fwpsl.redis;

/**
 * string类型操作
 *
 * @auther: 风戏fw
 * @date: 2020/11/21
 */
public interface IJedisStringClient {

    /**
     * 如果 key 已经存在并且是一个字符串， APPEND 命令将 value 追加到 key 原来的值的末尾。
     * 如果 key 不存在， APPEND 就简单地将给定 key 设为 value
     *
     * @param key
     * @param value
     * @return 追加 value 之后， key 中字符串的长度
     */
    int append(String key, String value);

    /**
     * 计算给定字符串中，被设置为 1 的比特位的数量
     *
     * @param key
     * @param start
     * @param end
     * @return 被设置为 1 的位的数量
     */
    int bitCount(String key, int start, int end);

    /**
     * 对一个或多个保存二进制位的字符串 key 进行位元操作，并将结果保存到 destkey 上。
     * <p>
     * operation 可以是 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种：
     * BITOP AND destkey key [key ...] ，对一个或多个 key 求逻辑并，并将结果保存到 destkey 。
     * BITOP OR destkey key [key ...] ，对一个或多个 key 求逻辑或，并将结果保存到 destkey 。
     * BITOP XOR destkey key [key ...] ，对一个或多个 key 求逻辑异或，并将结果保存到 destkey 。
     * BITOP NOT destkey key ，对给定 key 求逻辑非，并将结果保存到 destkey 。
     * 除了 NOT 操作之外，其他操作都可以接受一个或多个 key 作为输入。
     * <p>
     * 处理不同长度的字符串:
     * 当 BITOP 处理不同长度的字符串时，较短的那个字符串所缺少的部分会被看作 0 。
     * 空的 key 也被看作是包含 0 的字符串序列。
     *
     * @param operation
     * @param destkey
     * @param keys
     * @return 保存到 destkey 的字符串的长度，和输入 key 中最长的字符串长度相等
     */
    int bitop(int operation, String destkey, String... keys);

    /**
     * 将 key 中储存的数字值减一。
     * 如果 key 不存在，那么 key 的值会先被初始化为 0 ，然后再执行 DECR 操作。
     * 如果值包含错误的类型，或字符串类型的值不能表示为数字，那么返回一个错误。
     * 本操作的值限制在 64 位(bit)有符号数字表示之内。
     * <p>
     * 时间复杂度：O(1)
     *
     * @param key
     * @return 执行decr之后的值
     */
    long decr(String key);

    /**
     * 将 key 所储存的值减去减量 decrement 。
     * 如果 key 不存在，那么 key 的值会先被初始化为 0 ，然后再执行 DECRBY 操作。
     * 如果值包含错误的类型，或字符串类型的值不能表示为数字，那么返回一个错误。
     * 本操作的值限制在 64 位(bit)有符号数字表示之内
     * <p>
     * 时间复杂度：O(1)
     *
     * @param key
     * @param decrement
     * @return 减去decrement之后的值
     */
    long decrBy(String key, long decrement);

    /**
     * 返回 key 所关联的字符串值
     * <p>
     * 时间复杂度：O(1)
     *
     * @param key
     * @return 当 key 不存在时，返回 nil，否则，返回 key 的值。 如果 key不是字符串类型，那么返回一个错误。
     */
    String get(String key);

    /**
     * 对 key 所储存的字符串值，获取指定偏移量上的位(bit)
     * <p>
     * 时间复杂度：O(1)
     *
     * @param key
     * @param offset
     * @return 字符串值指定偏移量上的位(bit); 当offset比字符串值的长度大，或者key不存在时，返回 0
     */
    byte getbit(String key, int offset);

    /**
     * 返回 key 中字符串值的子字符串，字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)
     * <p>
     * 时间复杂度： O(N)，N 为要返回的字符串的长度。
     * 复杂度最终由字符串的返回值长度决定，但因为从已有字符串中取出子字符串的操作非常廉价(cheap)，
     * 所以对于长度不大的字符串，该操作的复杂度也可看作O(1)。
     *
     * @param key
     * @param start
     * @param end
     * @return 截取得出的子字符串
     */
    String getRange(String key, int start, int end);

    /**
     * 将给定 key 的值设为 value ，并返回 key 的旧值(old value)
     * 当 key 存在但不是字符串类型时，返回一个错误
     * <p>
     * 时间复杂度：O(1)
     *
     * @param key
     * @param value
     * @return 返回key的旧值；key不存在时，返回nil
     */
    String getSet(String key, String value);

    /**
     * 将 key 中储存的数字值增一。
     * 如果 key 不存在，那么 key 的值会先被初始化为 0 ，然后再执行 INCR 操作。
     * 如果值包含错误的类型，或字符串类型的值不能表示为数字，那么返回一个错误。
     * 本操作的值限制在 64 位(bit)有符号数字表示之内。
     * <p>
     * 时间复杂度：O(1)
     *
     * @param key
     * @return 执行命令之后 key 的值
     */
    long incr(String key);

    /**
     * 将 key 所储存的值加上增量 increment 。
     * 如果 key 不存在，那么 key 的值会先被初始化为 0 ，然后再执行 INCRBY 命令。
     * 如果值包含错误的类型，或字符串类型的值不能表示为数字，那么返回一个错误。
     * 本操作的值限制在 64 位(bit)有符号数字表示之内
     * <p>
     * 时间复杂度：O(1)
     *
     * @param key
     * @param increment
     * @return 执行命令之后 key 的值
     */
    long incrBy(String key, long increment);

    /**
     * 为 key 中所储存的值加上浮点数增量 increment 。
     * 如果 key 不存在，那么 INCRBYFLOAT 会先将 key 的值设为 0 ，再执行加法操作。
     * 如果命令执行成功，那么 key 的值会被更新为（执行加法之后的）新值，并且新值会以字符串的形式返回给调用者
     * <p>
     * 时间复杂度：O(1)
     *
     * @param key
     * @param increment
     * @return
     */
    double incrByFloat(String key, double increment);

    /**
     * 返回所有(一个或多个)给定 key 的值。
     * 如果给定的 key 里面，有某个 key 不存在，那么这个 key 返回特殊值 nil 。因此，该命令永不失败
     * <p>
     * 时间复杂度：O(N) , N为给定 key 的数量
     *
     * @param keys
     * @return 一个包含所有给定 key 的值的列表
     */
    String[] mget(String... keys);

    /**
     * 同时设置一个或多个 key-value 对。
     * 如果某个给定 key 已经存在，那么 MSET 会用新值覆盖原来的旧值，
     * 如果这不是你所希望的效果，请考虑使用 MSETNX 命令：它只会在所有给定 key 都不存在的情况下进行设置操作。
     * MSET 是一个原子性(atomic)操作，所有给定 key 都会在同一时间内被设置
     * <p>
     * 时间复杂度：O(N)， N 为要设置的 key 数量
     *
     * @param keyValues key-value对
     * @return
     */
    boolean mset(String... keyValues);

    /**
     * 同时设置一个或多个 key-value 对，当且仅当所有给定 key 都不存在。
     * 即使只有一个给定 key 已存在， MSETNX 也会拒绝执行所有给定 key 的设置操作。
     * MSETNX 是原子性的，因此它可以用作设置多个不同 key 表示不同字段(field)的唯一性逻辑对象(unique logic object)，
     * 所有字段要么全被设置，要么全不被设置。
     * <p>
     * 时间复杂度：O(N)， N 为要设置的 key 的数量。
     *
     * @param keyValues
     * @return 当所有 key 都成功设置，返回1；如果所有给定 key 都设置失败(至少有一个 key 已经存在)，那么返回 0
     */
    int msetnx(String... keyValues);

    /**
     * 与‘setex’相似，单位：毫秒
     *
     * @param key
     * @param milliseconds
     * @param value
     * @return
     */
    boolean psetex(String key, long milliseconds, String value);

    /**
     * 将字符串值 value 关联到 key 。
     * 如果 key 已经持有其他值， SET 就覆写旧值，无视类型。
     * 对于某个原本带有生存时间（TTL）的键来说， 当 SET 命令成功在这个键上执行时， 这个键原有的 TTL 将被清除。
     * <p>
     * 可选参数:
     * EX second ：设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。
     * PX millisecond ：设置键的过期时间为 millisecond 毫秒。 SET key value PX millisecond 效果等同于 PSETEX key millisecond value 。
     * NX ：只在键不存在时，才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value 。
     * XX ：只在键已经存在时，才对键进行设置操作
     * <p>
     * 时间复杂度：O(1)
     *
     * @param key
     * @param value
     * @return
     */
    boolean set(String key, String value);

    /**
     * 对 key 所储存的字符串值，设置或清除指定偏移量上的位(bit)。
     * 位的设置或清除取决于 value 参数，可以是 0 也可以是 1 。
     * 当 key 不存在时，自动生成一个新的字符串值。
     * 字符串会进行伸展(grown)以确保它可以将 value 保存在指定的偏移量上。当字符串值进行伸展时，空白位置以 0 填充。
     * offset 参数必须大于或等于 0 ，小于 2^32 (bit 映射被限制在 512 MB 之内)
     * <p>
     * 时间复杂度：O(1)
     *
     * @param key
     * @param offset
     * @param value
     * @return 指定偏移量原来储存的位
     */
    byte setbit(String key, int offset, byte value);

    /**
     * 将值 value 关联到 key ，并将 key 的生存时间设为 seconds (以秒为单位)
     * 如果 key 已经存在， SETEX 命令将覆写旧值
     * <p>
     * 时间复杂度：O(1)
     *
     * @param key
     * @param seconds
     * @param value
     * @return
     */
    boolean setex(String key, int seconds, String value);

    /**
     * 将 key 的值设为 value ，当且仅当 key 不存在。
     * 若给定的 key 已经存在，则 SETNX 不做任何动作。
     * SETNX 是『SET if Not eXists』(如果不存在，则 SET)的简写
     * <p>
     * 时间复杂度：O(1)
     *
     * @param key
     * @param value
     * @return 设置成功，返回 1；设置失败，返回 0
     */
    byte setnx(String key, String value);

    /**
     * 用 value 参数覆写(overwrite)给定 key 所储存的字符串值，从偏移量 offset 开始。
     * 不存在的 key 当作空白字符串处理。
     * <p>
     * SETRANGE 命令会确保字符串足够长以便将 value 设置在指定的偏移量上，
     * 如果给定 key 原来储存的字符串长度比偏移量小(比如字符串只有 5 个字符长，但你设置的 offset 是 10 )，
     * 那么原字符和偏移量之间的空白将用零字节(zerobytes, "\x00" )来填充。
     * <p>
     * 注意你能使用的最大偏移量是 2^29-1(536870911) ，
     * 因为 Redis 字符串的大小被限制在 512 兆(megabytes)以内。如果你需要使用比这更大的空间，你可以使用多个 key
     *
     * @param key
     * @param offset
     * @param value
     * @return 被 SETRANGE 修改之后，字符串的长度
     */
    int setrange(String key, int offset, String value);

    /**
     * 返回 key 所储存的字符串值的长度。
     * 当 key 储存的不是字符串值时，返回一个错误。
     * <p>
     * 时间复杂度：O(1)
     *
     * @param key
     * @return 字符串值的长度。当 key 不存在时，返回 0
     */
    int strlen(String key);

}
